contents

비교 연산자는 두 값(피연산자) 간의 관계를 평가하여 불리언(true 또는 false) 결과를 반환합니다. 기호는 거의 보편적이지만, 객체 대 기본 값(primitive)에 대한 연산자의 정확한 의미는 언어마다 상당히 다릅니다.

6가지 표준 비교 연산자는 다음과 같습니다.

각 언어별 구현과 미묘한 차이점을 자세히 설명해 드립니다.


C

C언어에서 비교는 직설적이지만, 최신 언어와는 한 가지 큰 차이점이 있습니다. C의 "불리언"은 단지 정수일 뿐입니다.


C++

C++은 C를 기반으로 하며, 진정한 불리언 타입과 연산자 오버로딩을 추가했습니다.

std::string s1 = "hello";
std::string s2 = "hello";
if (s1 == s2) { // 완벽하게 작동합니다.
	// ...
}

Java

Java에서는 기본 타입(primitive)과 객체(object)의 구분이 여기서 가장 중요한 세부 사항입니다.

// 기본 타입 예제
int a = 5;
int b = 5;
// a == b 는 TRUE

// 객체 예제
String s1 = new String("hi");
String s2 = new String("hi");

// s1 == s2 는 FALSE (메모리상 다른 객체임)
// s1.equals(s2) 는 TRUE (내용이 동일함)

Python

Python은 ==가 값을 확인하고, 별도의 연산자(is)가 동일성을 확인하도록 하여 단순화했습니다.

a = [1, 2, 3]
b = [1, 2, 3]

# a == b 는 True (값이 같음)
# a is b 는 False (메모리상 별개의 리스트 객체임)

c = a
# a is c 는 True (둘 다 동일한 객체를 가리킴)

Kotlin

Kotlin은 Java의 == 혼란을 "수정"하기 위해 설계되었습니다.

val s1 = "hi"
val s2 = "hi"
// s1 == s2 는 TRUE (.equals()를 호출하며, 결과가 true임)

val a = Integer(10)
val b = Integer(10)
// a == b 는 TRUE
// a === b 는 FALSE (서로 다른 객체임)

Rust

Rust는 트레이트(trait) 시스템을 통해 비교를 처리하여 컴파일 타임에 타입 안전성을 보장합니다.

#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
struct User {
	id: i32,
	name: String,
}

fn main() {
	let user1 = User { id: 1, name: "Alice".to_string() };
	let user2 = User { id: 1, name: "Alice".to_string() };
	let user3 = User { id: 2, name: "Bob".to_string() };

	// PartialEq를 파생시켰기 때문에 작동함
	if user1 == user2 {
		println!("user1과 user2는 같습니다");
	}

	// PartialOrd를 파생시켰기 때문에 작동함
	if user3 > user1 {
		println!("user3이 user1보다 큽니다");
	}
}

요약 표

언어 값 동등성 (내용) 동일성 (참조)
C strcmp(s1, s2) == 0 (문자열의 경우) ptr1 == ptr2
C++ s1 == s2 (오버로딩된 경우, 예: std::string) ptr1 == ptr2
Java obj1.equals(obj2) obj1 == obj2
Python obj1 == obj2 obj1 is obj2
Kotlin obj1 == obj2 (null-safe .equals()) obj1 === obj2
Rust obj1 == obj2 (PartialEq 트레이트 필요) std::ptr::eq(ptr1, ptr2) (명시적)

references